package com.fingard.dsp.bank.directbank.psbc02.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xml.security.Init;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.signature.SignedInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class MessageUtil {
    static Log log = LogFactory.getLog(MessageUtil.class);

    public static boolean xmlSignCheck(Document document, PublicKey publicKey) {
        boolean flag = false;

        Init.init();
        Element nscontext = XMLUtils.createDSctx(document, "ds",
                "http://www.w3.org/2000/09/xmldsig#");
        Element signElement = null;
        XMLSignature signature = null;
        try {
            signElement = (Element) XPathAPI.selectSingleNode(document,
                    "//ds:Signature[1]", nscontext);
        } catch (TransformerException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        if (signElement == null) {
            log.warn("signElement为空");
            return flag;
        }
        try {
            signature = new XMLSignature(signElement, null);
        } catch (XMLSignatureException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        } catch (XMLSecurityException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            log.error("===" + e.getMessage());
            e.printStackTrace();
        }
        try {
            flag = signature.checkSignatureValue(publicKey);
        } catch (XMLSignatureException e) {
            log.error("---" + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            log.error("===" + e.getMessage());
            e.printStackTrace();
        }
        log.info("验证签名结果：flag：[" + flag + "]");

        return flag;
    }

    public static String xmlSign(Document document, PrivateKey privateKey, String iid) {
        try {
            org.apache.xml.security.Init.init();
            XMLSignature sig = new XMLSignature(document, document.getDocumentURI(), "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
            sig.getSignedInfo().addResourceResolver(new OfflineResolver());

            Node messageNode = document.getElementsByTagName("Message").item(0);
            messageNode.appendChild(sig.getElement());

            Transforms transforms = new Transforms(document);

            transforms.addTransform("http://www.w3.org/2000/09/xmldsig#enveloped-signature");
            transforms.addTransform("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");

            sig.addDocument("#" + iid, transforms,
                    "http://www.w3.org/2000/09/xmldsig#sha1");


            sig.sign(privateKey);


            ByteArrayOutputStream os = new ByteArrayOutputStream();
            XMLUtils.outputDOMc14nWithComments(document, os);

            return os.toString("utf-8");
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    public static Document getXml(String message) {
        DocumentBuilderFactory docBuilderFactory =
                DocumentBuilderFactory.newInstance();
        docBuilderFactory.setNamespaceAware(true);
        DocumentBuilder documentBuilder = null;
        Document document = null;
        try {
            documentBuilder = docBuilderFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            log.error(e.getMessage());
            e.printStackTrace();
            return null;
        }
        try {
            document = documentBuilder.parse(new InputSource(new ByteArrayInputStream(message.getBytes("UTF-8"))));
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
            e.printStackTrace();
            return null;
        } catch (SAXException e) {
            log.error(e.getMessage());
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            log.error(e.getMessage());
            e.printStackTrace();
            return null;
        }
        return document;
    }

    public static Document getXml2(String message)
            throws ParserConfigurationException, UnsupportedEncodingException, SAXException, IOException {
        DocumentBuilderFactory docBuilderFactory =
                DocumentBuilderFactory.newInstance();
        docBuilderFactory.setNamespaceAware(true);
        DocumentBuilder documentBuilder = null;
        Document document = null;

        documentBuilder = docBuilderFactory.newDocumentBuilder();
        document = documentBuilder.parse(new InputSource(new ByteArrayInputStream(message.getBytes("UTF-8"))));


        return document;
    }

    public static Map<String, String> xmlToMap(Document document) {
        Map<String, String> map = new HashMap();
        NodeList nodeList = null;
        Node messageNode = null;
        Node tradeCodeNode = null;
        Node childNode = null;
        Node signNoNode = null;
        NamedNodeMap namedNodeMap = null;
        Attr attr = null;

        String nodeName = "";
        String nodeValue = "";
        String signNo = "";
        String CheckSerialNoList = "";

        String extensionName = "";
        String extensionValue = "";


        messageNode = document.getElementsByTagName("Message").item(0);
        namedNodeMap = messageNode.getAttributes();
        if (namedNodeMap != null) {
            attr = (Attr) namedNodeMap.item(0);
            nodeName = messageNode.getNodeName();
            nodeName = nodeName + (attr == null ? "id" : attr.getName());
            nodeValue = attr == null ? "" : attr.getValue();
            log.debug(nodeName + ":[" + nodeValue + "]");
            map.put(nodeName, nodeValue);
        }
        tradeCodeNode = messageNode.getFirstChild();
        while (tradeCodeNode.getNodeType() != 1) {
            tradeCodeNode = tradeCodeNode.getNextSibling();
        }
        log.debug("交易码：" + tradeCodeNode.getNodeName());
        map.put("tradeCode", tradeCodeNode.getNodeName());

        namedNodeMap = tradeCodeNode.getAttributes();
        if (namedNodeMap != null) {
            attr = (Attr) namedNodeMap.item(0);
            nodeName = tradeCodeNode.getNodeName();
            nodeName = nodeName + (attr == null ? "id" : attr.getName());
            nodeValue = attr == null ? "" : attr.getValue();
            log.debug(nodeName + ":[" + nodeValue + "]");
            map.put(nodeName, nodeValue);
        }
        childNode = tradeCodeNode.getFirstChild();
        while (childNode.getNodeType() != 1) {
            childNode = childNode.getNextSibling();
        }
        nodeName = childNode.getNodeName();
        nodeValue = childNode.getFirstChild() == null ? "" : childNode.getFirstChild().getNodeValue();
        log.debug(nodeName + ":[" + nodeValue + "]");
        map.put(nodeName, nodeValue);
        while ((childNode = childNode.getNextSibling()) != null) {
            if (childNode.getNodeType() == 1) {
                nodeName = childNode.getNodeName();
                if ("CheckSerialNoList".equals(nodeName)) {
                    nodeList = childNode.getChildNodes();
                    for (int i = 0; i < nodeList.getLength(); i++) {
                        signNoNode = nodeList.item(i);
                        signNo = signNoNode.getTextContent() == null ? "null" : signNoNode.getTextContent();

                        log.debug(signNoNode.getNodeName() + "=[" + signNo + "]");

                        CheckSerialNoList = CheckSerialNoList + signNo + ",";
                    }
                    log.debug("CheckSerialNoList=[" + CheckSerialNoList + "]");
                    nodeValue = CheckSerialNoList.substring(0, CheckSerialNoList.lastIndexOf(","));
                    log.debug("nodeValue=[" + nodeValue + "]");

                    log.debug(nodeName + ":[" + nodeValue + "]");
                    map.put(nodeName, nodeValue);
                } else if (("extension".equals(nodeName)) && (childNode.getFirstChild() != null)) {
                    NodeList list = childNode.getChildNodes();
                    for (int i = 0; i < list.getLength(); i++) {
                        if (list.item(i).getNodeType() == 1) {
                            if ("name".equals(list.item(i).getNodeName())) {
                                extensionName = list.item(i).getTextContent();
                            }
                            if ("value".equals(list.item(i).getNodeName())) {
                                extensionValue = list.item(i).getTextContent();
                            }
                        }
                    }
                    log.debug(extensionName + "=[" + extensionValue + "]");
                    map.put(extensionName, extensionValue);
                } else {
                    nodeValue = childNode.getTextContent() == null ? "null" : childNode.getTextContent();
                    log.debug(nodeName + ":[" + nodeValue + "]");
                    nodeValue = nodeValue.replace("|", "");
                    map.put(nodeName, nodeValue);
                }
            }
        }
        return map;
    }

    public static String filterMessage(String inputMessage) {
        String outMessage = "";


        Pattern p = Pattern.compile("\t|\r|\n");
        Matcher m = p.matcher(inputMessage);
        outMessage = m.replaceAll("");


        return outMessage;
    }

    public static void main(String[] args) {
    }
}
